#include "utils.h"
#include <iostream>
#include <fstream>
#include <sstream>

namespace common {

bool IsBlank(char c) 
{
	return c == ' ' || c == '\n' || c == '\t';
}

bool IsKey(const std::string &s) 
{
    return KEYWORDS.count(s) > 0;
}

bool IsDigit(char c) 
{
    return c >= '0' && c <= '9';
}

bool IsLetter(char c) 
{
    return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
}

bool IsOperator(char c) 
{
    return c == '+' || c == '-' || c == '*' || c == '/' || c == '^';
}

bool IsSeparator(char c) 
{
    return  ',' == c || ';' == c || '{' == c || '}' == c || '(' == c || ')' == c;
}

std::string trim(const std::string& str) 
{
    size_t first = str.find_first_not_of(" \t\n\r");
    if (first == std::string::npos) 
    {
        return "";  // if all the characters are blank-char, then return ""
    }
    size_t last = str.find_last_not_of(" \t\n\r");
    return str.substr(first, last - first + 1);
}

std::string ReadFromFileAndTrim(const std::string &path) 
{
    std::ifstream file(path);  // open a file.
    if (!file.is_open()) 
    {
        std::cerr << "cannot open the file: " << path << std::endl;
        throw std::runtime_error("cannot open the file: " + path);
    }

    std::stringstream buffer;
    buffer << file.rdbuf();  // read the file content to a stringstream
    std::string content = buffer.str();

    return trim(content);  // trimming.
}

void Printer(WordType tp, const std::string &s) 
{
    if (tp == ERROR) 
    {
		std::cout << "ERROR: " << s << std::endl;
	} 
    else 
    {
		std::cout << "( " << std::to_string(tp) << ", \"" << s << "\" )" << std::endl;
	}
}

uint16_t CharsToUint16(char first, char second) 
{
    return (static_cast<uint16_t>(first) << 8) | static_cast<uint16_t>(second);
}

std::pair<char, char> Uint16ToChars(uint16_t value) 
{
    char first = static_cast<char>((value >> 8) & 0xFF);
    char second = static_cast<char>(value & 0xFF);
    return {first, second};
}

std::string PadColumn(const std::string &content, int width) 
{
    int current = content.size();
    if (current >= width) 
    {
        return content.substr(0, width/2); // more operations for UTF-8 safety needed.
    }
    return content + std::string(width - current, ' ');
}

} // namespace common